
/*
 * 
 * 斗地主之顺子
 * 
 * 题目描述

在斗地主扑克牌游戏中， 扑克牌由小到大的顺序为：3,4,5,6,7,8,9,10,J,Q,K,A,2，玩家可以出的扑克牌阵型有：单张、对子、顺子、飞机、炸弹等。

其中顺子的出牌规则为：由至少5张由小到大连续递增的扑克牌组成，且不能包含2。

例如：{3,4,5,6,7}、{3,4,5,6,7,8,9,10,J,Q,K,A}都是有效的顺子；而{J,Q,K,A,2}、 {2,3,4,5,6}、{3,4,5,6}、{3,4,5,6,8}等都不是顺子。

给定一个包含 13 张牌的数组，如果有满足出牌规则的顺子，请输出顺子。

如果存在多个顺子，请每行输出一个顺子，且需要按顺子的第一张牌的大小（必须从小到大）依次输出。

如果没有满足出牌规则的顺子，请输出No。

输入描述
13张任意顺序的扑克牌，每张扑克牌数字用空格隔开，每张扑克牌的数字都是合法的，并且不包括大小王：2 9 J 2 3 4 K A 7 9 A 5 6

不需要考虑输入为异常字符的情况

输出描述
组成的顺子，每张扑克牌数字用空格隔开：3 4 5 6 7

用例
输入	2 9 J 2 3 4 K A 7 9 A 5 6
输出	3 4 5 6 7
说明	13张牌中，可以组成的顺子只有1组：3 4 5 6 7。
输入	2 9 J 10 3 4 K A 7 Q A 5 6
输出	
3 4 5 6 7
9 10 J Q K A
说明	13张牌中，可以组成2组顺子，从小到大分别为：3 4 5 6 7 和 9 10 J Q K A
输入	2 9 9 9 3 4 K A 10 Q A 5 6
输出	No
说明	13张牌中，无法组成顺子。

 */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

/**
  * 
  题目解析
先看一个例子：

3 4 5 6 6 7 7 8 9 10
这个例子该输出什么呢？

如果是优先最长顺子的话，那么应该输出：

3 4 5 6 7 8 9 10
如果是优先最多顺子的话，那么应该输出：

3 4 5 6 7
6 7 8 9 10
当前博客解法是按照 “优先最长顺子” 实现的

2023.07.10

之前有考友在评论区反馈 优先最长顺子解法的通过率是80%，今天评论区又有一个考友提供了一个用例：

3 4 5 6 7 3 4 5 6 7 A A A
之前，优先最长顺子解法是基于栈结构实现的，在测试该用例时，产生死循环。因此我怀疑20%未通过的用例就是类似于这个。

现在我对优先最长顺子解法做了更新优化，已支持该类型用例，大家考试时可以尝试使用优先最长顺子解法。

优先最长顺子解法

我的解题思路如下：

首先定义一个card2Num方法，即将字符串牌面 映射为 数值。具体映射关系可看代码中card2Num方法的实现。

然后，将输入的牌数组，按照card2Num映射的数值，进行升序排序。

之后，我创建多个顺子容器，外层遍历牌数组，内层遍历顺子容器：

如果顺子容器是空的，则直接将当前牌加入该顺子容器
如果顺子容器不是空的，则比较当前牌cur 和 顺子容器尾牌tail
如果cur - tail = 1，则当前牌cur可以加入当前顺子尾部。
如果cur - tail != 1，则当前牌cur不能加入当前顺子尾部，我们应该继续尝试将cur拼接到下一个顺子容器的尾部。
按照上面逻辑，我们最后可以得到多个顺子容器，我们需要过滤掉其中长度小于5的顺子，如果过滤完后没有了，则打印输出“No”，如果过滤完后还有，则剩余顺子容器按照 第一张牌数值 从小到大排序后，依次打印。
  */
public class 斗地主之顺子 {
    
    public static void main(String[] args) {


        Scanner scanner = new Scanner(System.in);

        //获取输入，直接过滤掉 2
        String[] cardArr = Arrays.stream(scanner.nextLine().split(" "))
        .filter(s -> !"2".equals(s)).toArray(String[]::new);

        List<Integer> cardIntList = new ArrayList<>(cardArr.length);

        for(String str : cardArr){

            if(str.equalsIgnoreCase("j")){
                cardIntList.add(11);
            } else if(str.equalsIgnoreCase("q")){
                cardIntList.add(12);
            } else if(str.equalsIgnoreCase("k")){
                cardIntList.add(13);
            } else if(str.equalsIgnoreCase("a")){
                cardIntList.add(14);
            } else{

                cardIntList.add(Integer.parseInt(str));
            }
        }

        //排序
        Collections.sort(cardIntList);

        //cardIntList.stream().forEach(System.out::println);


        //获取顺子业务操作

        ArrayList<ArrayList<Integer>> straights = new ArrayList<>();

        for(int cardNum: cardIntList){
            int i=0;

            for (; i < straights.size(); i++) {

                ArrayList<Integer> straight = straights.get(i);

                int back = straight.get(straight.size()-1);

                if(cardNum - back == 1){

                    //如果card牌面比顺子最后一张牌面大1，则可以拼接到该顺子尾部
                    straight.add(cardNum);
                    break;

                }
            }

            // 如果card无法拼接到已有顺子的尾部, 则重新建立一个顺子, 该顺子以card开头
            if (i == straights.size()) {
                ArrayList<Integer> straight = new ArrayList<>();
                straight.add(cardNum);
 
                straights.add(straight);
            }

        }

        //处理顺子列表
        int straightCount = 0;

        for(List<Integer> straight : straights){

            if(straight.size() < 5){

                continue;
            }

            straightCount ++;

            // straight.stream().map(s -> {

            //     if(s == 11){
            //         return "J ";
            //     } else if(s == 12){
            //         return "Q ";
            //     } else if(s == 13){
            //         return "K ";
            //     } else if(s == 14){
            //         return "A ";
            //     }

            //     return s+" ";
            // }).forEach(System.out::print);

            StringBuilder builder = new StringBuilder();
            for(int num : straight){
                if(num == 11){
                    builder.append("J ");
                } else if(num == 12){
                    builder.append("Q ");
                } else if(num == 13){
                    builder.append("K ");
                } else if(num == 14){
                    builder.append("A ");
                } else {

                    builder.append(num+" ");
                }

            }
            System.out.println(builder.toString());

        }

        if(straightCount == 0){

            System.out.println("No");

        }

    }
}
